package main

import (
	"encoding/json"
	"fmt"
	"net"
	"unsafe"
)

// 定义goroutine之间的消息传递结构
type ChatMsg struct {
	From, To, Msg string
}

// 定义客户端服务器之间的消息传递结构
type ClientMsg struct {
	To      string  `json:"to"`
	MsgType int     `json:"msgtype"`
	Msg     string  `json:"msg"`
	Datalen uintptr `json:"datalen"`
}

// 消息中心的通道
var chan_msgcenter chan ChatMsg

// 定义连接列表
var mapClients map[string]net.Conn
var keyClients map[string]string

/*
*
服务端启动端口，循环监听链接，获得链接后启动一个线程读取服务器监听要发送的数据，发送时，再次启动线程，处理发送逻辑
服务端继续for循环获得链接，每当获得链接后，启动线程持有该连接for循环读取链接数据并发送
*/
func main() {
	//初始化数据
	chan_msgcenter = make(chan ChatMsg)
	mapClients = make(map[string]net.Conn)
	keyClients = make(map[string]string)

	//设置侦听
	listen, err := net.Listen("tcp", "localhost:8080")
	if err != nil {
		fmt.Println(err)
	}
	defer listen.Close()

	//启动消息中心处理
	go msg_center()

	//for循环处理客户端请求
	for {
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("Failed to accept ", err)
			continue
		}
		//处理请求
		go handle_conn(conn)

	}
}

/*
*
断开连接
*/
func logout(conn net.Conn, from string) {

	defer conn.Close()
	msg := ChatMsg{
		from, "all", from + "-> logout"}
	chan_msgcenter <- msg
	delete(mapClients, from)
}

/*
*
处理请求的函数
*/
func handle_conn(conn net.Conn) {
	//1.拿到客户端信息
	from := conn.RemoteAddr().String()
	defer logout(conn, from)

	//2.放到maps中
	mapClients[from] = conn

	//发送上线消息
	msg := ChatMsg{from, "all", from + "->login"}
	chan_msgcenter <- msg

	//3.处理读写行为
	buf := make([]byte, 1024)
	for {
		n, err := conn.Read(buf)
		if err != nil {
			fmt.Println("failed to read data ", err)
		}
		//处理客户端的消息请求
		var climsg ClientMsg
		err = json.Unmarshal(buf[:n], &climsg)
		if err != nil {
			fmt.Println("Failed to unmarshal ", err)
			continue
		}
		//这一步不知道干什么？
		if climsg.Datalen != unsafe.Sizeof(climsg) {
			fmt.Println("message format err ", climsg)
			continue
		}

		fmt.Println(climsg)

		//组织一个消息
		from := conn.RemoteAddr().String()
		chatMsg := ChatMsg{from, "all", climsg.Msg}
		switch climsg.MsgType {
		case SETNAME:
			keyClients[climsg.Msg] = from
			chatMsg.Msg = from + "set name= " + climsg.Msg + " success"
			chatMsg.From = "server"
		case BROADCAST:
		case PRIVATE:
			chatMsg.To = climsg.To
		}
		chan_msgcenter <- chatMsg
	}
}

/*
*
定义消息类型
*/
const (
	LOGIN = iota
	LOGOUT
	SETNAME
	BROADCAST
	PRIVATE
)

/*
*
定义消息处理中心
*/
func msg_center() {
	for {
		msg := <-chan_msgcenter
		//发送：广播或私信
		fmt.Println(msg)
		go send_msg(msg)
	}
}

/*
*
发送消息
*/
func send_msg(msg ChatMsg) {
	data, err := json.Marshal(msg)
	if err != nil {
		fmt.Println("failed to Marshal", err)
		return
	}
	//广播
	if msg.To == "all" {
		for _, conn := range mapClients {
			if msg.From != conn.RemoteAddr().String() {
				conn.Write(data)
			}
		}
		//私信
	} else {
		from, ok := keyClients[msg.To]
		if !ok {
			fmt.Println("no such client", msg.To)
			return
		}
		conn, ok := mapClients[from]
		if !ok {
			fmt.Println("no such client", from)
			return
		}
		conn.Write(data)
	}
}
